//
// Created by wujehy on 2020/8/5.
//

#include <Dao/IoTDB.h>
#include <Context/TaskContext.h>
#include <NetWorkModule/ContextDataType.h>
#include <sstream>
#include <Tool/GeeJoanMD5.h>
#include "IoTMod.h"
#include "GeeJoan/IoTModule.pb.h"
#include "GeeJoan/NetWorkPackage.pb.h"
#include "NetWorkWarpper.h"
#include "handy/handy.h"
#include "Tool/Common.h"

using namespace GeeJoan::Common;
using handy::Logger;

//#include "GeeJoan/NetWorkPackage.pb.h"
int IoTMod::type()
{
    return this->Mod_IoT;
}

int IoTMod::depackage(int taskid, int type_, void *data, int len, void *userdata)
{
    // 通过类型分发事件
    auto find = m_type_event_map.find( type_ );
    if (find != m_type_event_map.end())
    {
        return find->second( taskid, data, len, userdata );
    } else
    {
        return -2;
    }
}

void IoTMod::setBusinessManager(BusinessManager *hander)
{
    businessManager = hander;
}

IoTMod::IoTMod()
{
    init_callback_function();

    init_event();
}

std::string GeeJoan::Common::genTaskCode()
{
    std::stringstream ss;
    ss << "task" << handy::util::timeMicro();
    return ss.str();
}

static std::string genNewDeviceToken(uint64_t Gid, uint64_t did)
{
    // TODO  Token 生成规则
    std::stringstream ss;
    ss << "testToken." << Gid << "." << did << "." << handy::util::timeMicro();
    return ss.str();
}

void IoTMod::init_callback_function()
{
    using namespace GeeJoan::Protocol;
    using namespace handy;
    uploadSensor_event_function = [&](int taskid, void *data, int len, void *userdata)
    {
        IoT::UploadSensorDataAPI uploadSensorDataApi;
        if (!uploadSensorDataApi.ParseFromArray( data, len ))
        {
            // 失败
            businessManager->call500( taskid, "error" );
            return -1;
        }

        // 查找当前设备信息
        auto taskdata = businessManager->getContextManager()->get<TaskContext>( taskid, 1 );
        auto conn = businessManager->getNetWorkWarpper()->m_id_client_map[taskdata->tcpid];

        if (conn->context<ContextDataType>().tokenstr.empty())
        {
//             失败
            businessManager->call500( taskid, "device Not Login" );
            return -1;
        }

        SensorDataType sensorDataType;
        sensorDataType.GatewayId = uploadSensorDataApi.gatewayid();
        sensorDataType.DeviceId = uploadSensorDataApi.deviceid();
        sensorDataType.permission = uploadSensorDataApi.permission();
        sensorDataType.uid = conn->context<ContextDataType>().uid;
        sensorDataType.key = uploadSensorDataApi.key();
        // 储存的数据
        // TODO 这里 进行 HEX 储存
        sensorDataType.data = StringToHex( uploadSensorDataApi.data());
//
//        DataBaseHelper dataBaseHelper( DATABASENAME );
        int result = ioTTable->insertData( sensorDataType );

        if (result == EXIT_SUCCESS)
        {
            std::string outstring = "";
            businessManager->call200( taskid, outstring );
        } else
        {
            businessManager->call500( taskid, "upload Data Fail " );
        }

        return 0;
    };
    findSensor_event_function = [&](int taskid, void *data, int len, void *userdata)
    {
        IoT::FindSensorDataRequest findSensorDataRequest;
        if (!findSensorDataRequest.ParseFromArray( data, len ))
        {
            // 失败
            businessManager->call500( taskid, "error" );
            return -1;
        }

        uint64_t gatewayid = findSensorDataRequest.gatewayid();
        uint64_t deviceid = findSensorDataRequest.deviceid();

//        int64_t currUid = context->con->context<ServerContext>().getUid();

//        DataBaseHelper dataBaseHelper( DATABASENAME );

        // 查找当前设备信息
        auto taskdata = businessManager->getContextManager()->get<TaskContext>( taskid, 1 );
        auto conn = businessManager->getNetWorkWarpper()->m_id_client_map[taskdata->tcpid];
        int64_t currUid = conn->context<ContextDataType>().uid;
        int ret = ioTTable->checkMyDevice( currUid, gatewayid, deviceid );


        std::vector<SensorDataType> datas;

        if (ret == EXIT_SUCCESS)
        {
            // 我的数据
            ioTTable->findDataByUid( datas,
                                     0,
                                     gatewayid,
                                     deviceid,
                                     1,
                                     findSensorDataRequest.key(),
                                     findSensorDataRequest.size(),
                                     findSensorDataRequest.direction(),
                                     findSensorDataRequest.time()
            );

        } else
        {
            ioTTable->findDataByPublic(
                    datas,
                    findSensorDataRequest.gatewayid(),
                    findSensorDataRequest.deviceid(),
                    findSensorDataRequest.size(),
                    findSensorDataRequest.direction(),
                    findSensorDataRequest.time()
            );
        }

        IoT::FindSensorDataRespose findSensorDataRespose;
        findSensorDataRespose.set_gatewayid( gatewayid );
        findSensorDataRequest.set_deviceid( deviceid );
        //

        for (auto data :datas)
        {
            IoT::SensorDataPackage *tempSensorDataPackage = nullptr;
            tempSensorDataPackage = findSensorDataRespose.add_datas();
            tempSensorDataPackage->set_key( data.key );
            tempSensorDataPackage->set_data( HexToString( data.data ));
            tempSensorDataPackage->set_time( data.create );
        }
        std::string outstring;


        if (findSensorDataRespose.SerializeToString( &outstring ))
        {
            businessManager->call200( taskid, outstring );
        } else
        {
            businessManager->call500( taskid, "error" );
        }
        return 0;
    };
    controlDevice_event_function = [&](int taskid, void *data, int len, void *userdata)
    {
        // 收到 设备控制的操作
        IoT::ControlDeviceRequest controlDeviceRequest;

        if (!controlDeviceRequest.ParseFromArray( data, len ))
        {
            // 失败
            businessManager->call500( taskid, "not found device" );
            return -1;
        }
        //
        // 查找当前设备信息
        auto taskdata = businessManager->getContextManager()->get<TaskContext>( taskid, 1 );
        auto conn = businessManager->getNetWorkWarpper()->m_id_client_map[taskdata->tcpid];
        std::string serverToken = conn->context<ContextDataType>().deviceToken;

        std::string currentTaskCode = genTaskCode();
        std::string currentToken = controlDeviceRequest.token();
        uint64_t currentGatewayId = controlDeviceRequest.gatewayid();
        uint64_t currentDevideId = controlDeviceRequest.deviceid();


        DeviceDataType deviceDataType;
        int64_t serverTime = handy::util::timeMilli();
        int result = ioTTable->findDeviceByToken( deviceDataType, currentToken );

        if (result == SUCCESS)
        {
            // 查找成功
            info( "IoTBusiness::ControlDevice find success ! " );
            // 存在 这个设备
            // 直接向这个设备 发送请求
            auto findDevice = m_token_client_map.find( currentToken );
            if (findDevice != m_token_client_map.end())
            {
                IoT::ControlDeviceListerner controlDeviceListerner;
                info( "IoTBusiness::ControlDevice control success " );
                controlDeviceListerner.set_time( serverTime );
                controlDeviceListerner.set_taskcode( currentTaskCode );
                controlDeviceListerner.set_data( controlDeviceRequest.data());
                std::string sendMessage;
                controlDeviceListerner.SerializePartialToString( &sendMessage );

                NetWork::NetWorkPackageRespose respose;
                // TODO
                respose.set_type_m( NetWork::NetWorkPackageModel::IOTMod );
                respose.set_type_sub( IOT_CONTROL_LISTERNER );
                respose.set_taskid( 0 );
                respose.set_body( sendMessage );
                respose.set_code(200);

                std::string out;
                respose.SerializeToString( &out );
                findDevice->second->send( out );

                // 加入 taskmap
                m_device_code_client_map.insert( {currentTaskCode, conn} );
            }

//            auto findDevice = CacheManager::GetInstance()->deviceTokenMap.find( currentToken );
//            if (findDevice != CacheManager::GetInstance()->deviceTokenMap.end())
//            {
//                IoT::ControlDeviceListerner controlDeviceListerner;
//
//                info( "IoTBusiness::ControlDevice control success " );
//                controlDeviceListerner.set_time( serverTime );
//                controlDeviceListerner.set_taskcode( currentTaskCode );
//                controlDeviceListerner.set_data( controlDeviceRequest.data());
//                std::string sendMessage;
//                controlDeviceListerner.SerializePartialToString( &sendMessage );
////            mod_currSubType = IOT_CONTROL_LISTERNER;
//                call200( NETWORK_MOD_TYPE_IOT, IOT_CONTROL_LISTERNER, 0, findDevice->second, sendMessage );
////            mod_currSubType = IOT_CONTROL_DEVICE;
////            controlDeviceAckListerner
//
//                // 加入 taskmap
//
////                CacheManager::GetInstance()->taskCodeMap[currentTaskCode] = context->con;
//
//            }
        }


        IoT::ControlDeviceRespose controlDeviceRespose;


        controlDeviceRespose.set_taskcode( currentToken );
        controlDeviceRespose.set_time( serverTime );
        std::string outstring;

        if (controlDeviceRespose.SerializePartialToString( &outstring ))
        {
            businessManager->call200( taskid, outstring );
            info( " IoTBusiness::ControlDevice : success " );
            return 0;
        } else
        {
            businessManager->call500( taskid, " error " );
            return -1;
        }

    };
    controlDeviceAck_event_function = [&](int taskid, void *data, int len, void *userdata)
    {
        IoT::ControlDeviceAckAPI controlDeviceAckApi;

        if (!controlDeviceAckApi.ParseFromArray( data, len ))
        {
            businessManager->call500( taskid, " error " );
            return -1;
        }

        info( "IoTBusiness::ControlDeviceListerner , enter success ... " );
        std::string respTaskcode = controlDeviceAckApi.taskcode();

        auto findDevice = m_device_code_client_map.find( respTaskcode );
        if (findDevice != m_device_code_client_map.end())
        {
            // 找到
            IoT::ControlDeviceAckListerner controlDeviceAckListerner;
            controlDeviceAckListerner.set_taskcode( respTaskcode );
            controlDeviceAckListerner.set_errcode( controlDeviceAckApi.errcode());
            controlDeviceAckListerner.set_errormsg( controlDeviceAckApi.errormsg());
            controlDeviceAckListerner.set_time( util::timeMilli());

            std::string outString;

            controlDeviceAckListerner.SerializePartialToString( &outString );
            NetWork::NetWorkPackageRespose respose;
            respose.set_type_m( NetWork::NetWorkPackageModel::IOTMod );
            respose.set_type_sub( IOT_CONTROL_ACK_LISTERNER );
            respose.set_taskid( 0 );
            respose.set_code(200);
            respose.set_body( outString );
            std::string out;
            respose.SerializeToString( &out );
            findDevice->second->send( out );
            info( "IoTBusiness::ControlDeviceListerner find success" );
            // 移除队列
            m_device_code_client_map.erase( findDevice );
        }

        std::string outString = "";
        businessManager->call200( taskid, outString );

        return 0;
    };
    loginDevice_event_function = [&](int taskid, void *data, int len, void *userdata)
    {
        IoT::LoginDeviceAPI loginDeviceApi;

        if (!loginDeviceApi.ParseFromArray( data, len ))
        {
            // 失败
            businessManager->call500( taskid, "error" );
            return -1;
        }

        //
        std::string currentDeviceToken = loginDeviceApi.token();
        // 查找当前设备信息
        auto taskdata = businessManager->getContextManager()->get<TaskContext>( taskid, 1 );
        auto conn = businessManager->getNetWorkWarpper()->m_id_client_map[taskdata->tcpid];

        std::string serverToken = conn->context<ContextDataType>().tokenstr;

        if (serverToken.empty() || serverToken != currentDeviceToken)
        {
            info( "IoTBusiness::LoginDevice %s ", serverToken.c_str());
        }

//        DataBaseHelper dataBaseHelper( DATABASENAME );

        int result = ioTTable->loginDeviceByToken( currentDeviceToken );

        if (result != SUCCESS)
        {
            // 失败
            businessManager->call500( taskid, "not found device" );
            return -1;
        }

        // 成功 更新 token

        // 找到 uid
        DeviceDataType deviceDataType;
        ioTTable->findDeviceByToken( deviceDataType, currentDeviceToken );


        conn->context<ContextDataType>().tokenstr = currentDeviceToken;

        conn->context<ContextDataType>().uid = deviceDataType.uid;

        std::string outstring = "";

        businessManager->call200( taskid, outstring );

        auto pt = m_token_client_map.insert( {currentDeviceToken, conn} );
        if (pt.second)
        {
            info( " IoTBusiness::LoginDevice , add deviceTokenMap success " );
        } else
        {
            info( " IoTBusiness::LoginDevice , add deviceTokenMap fail " );
        }

        return 0;
    };
    deviceHeartBeat_event_function = [&](int taskid, void *data, int len, void *userdata)
    {
        //TODO
        return -2;
    };
    createDevice_event_function = [&](int taskid, void *data, int len, void *userdata)
    {
        IoT::CreateDeviceRequest createDeviceRequest;

        if (!createDeviceRequest.ParseFromArray( data, len ))
        {
            // 失败
            businessManager->call500( taskid, "error" );
            return -1;
        }
        // 解包成功
        auto taskdata = businessManager->getContextManager()->get<TaskContext>( taskid, 1 );
        auto conn = businessManager->getNetWorkWarpper()->m_id_client_map[taskdata->tcpid];
        int64_t currentUid = conn->context<ContextDataType>().uid;

        uint64_t currentGatewayid = createDeviceRequest.gatewayid();
        int32_t permission = createDeviceRequest.permission();
//

        std::string note = createDeviceRequest.note();

        uint64_t newDeviceId = 0;
        if (currentUid == 0)
        {
            // TODO 没有 登录  则 通过Token 查找当前 uid
        }

//        DataBaseHelper dataBaseHelper( DATABASENAME );
        int ret = -1;
        if (currentUid > 0)
        {
            // 存在
            ret = ioTTable->addDevice( currentUid, currentGatewayid, permission, note,
                                       newDeviceId );
            info( "IoTBusiness::FindGateway : CreateDevice success " );
        } else
        {
            info( "IoTBusiness::FindGateway : CreateDevice uid not find " );
            //
        }

        if (ret != SUCCESS)
        {
            // 失败
            businessManager->call500( taskid, "CreateDevice Fail ! " );
            return -1;
        }

        IoT::CreateDeviceRespose createDeviceRespose;

        createDeviceRespose.set_deviceid( newDeviceId );
        createDeviceRespose.set_time( util::timeMilli());

        std::string outString;

        if (createDeviceRespose.SerializeToString( &outString ))
        {
            businessManager->call200( taskid, outString );
            return 0;
        } else
        {
            // 失败
            businessManager->call500( taskid, "CreateDevice Fail !" );
            return -1;
        }

    };
    findDeviceToken_event_function = [&](int taskid, void *data, int len, void *userdata)
    {
        IoT::FindDeviceTokenRequest findDeviceTokenRequest;

        if (!findDeviceTokenRequest.ParseFromArray( data, len ))
        {
            // 失败
            businessManager->call500( taskid, "error" );
            return -1;
        }

        //
        // 解包成功
        auto taskdata = businessManager->getContextManager()->get<TaskContext>( taskid, 1 );
        auto conn = businessManager->getNetWorkWarpper()->m_id_client_map[taskdata->tcpid];
        int64_t currentUid = conn->context<ContextDataType>().uid;

        if (currentUid == 0)
        {
            // 通过 Token 查找 uid
        }

        uint64_t currentGatewayid = findDeviceTokenRequest.gatewayid();
        uint64_t currentDevideid = findDeviceTokenRequest.deviceid();


        DeviceDataType deviceDataType;
        int ret = ioTTable->findDeviceToken( deviceDataType, currentUid, currentGatewayid,
                                             currentDevideid );

        info( "IoTBusiness::FindDeviceToken , find ret = %d ", ret );
        if (ret == SUCCESS)
        {
            // 成功
            IoT::FindDeviceTokenRespose findDeviceTokenRespose;
            findDeviceTokenRespose.set_time( util::timeMilli());
            findDeviceTokenRespose.set_token( deviceDataType.Token );

            findDeviceTokenRespose.set_gatewayid( deviceDataType.GatewayId );
            findDeviceTokenRespose.set_deviceid( deviceDataType.DevideId );

            std::string outString;

            if (findDeviceTokenRespose.SerializePartialToString( &outString ))
            {
                // 成功
                businessManager->call200( taskid, outString );
            } else
            {
                businessManager->call500( taskid, "serial error " );
            }
            return 0;
        } else
        {
            // 失败
            businessManager->call500( taskid, " unknow Error " );
            return -1;
        }
    };
    generateDeviceToken_event_function = [&](int taskid, void *data, int len, void *userdata)
    {
        IoT::GenerateDeviceTokenRequest generateDeviceTokenRequest;

        if (!generateDeviceTokenRequest.ParseFromArray( data, len ))
        {
            // 失败
            businessManager->call500( taskid, "error" );
            return -1;
        }

        // 解包成功
        auto taskdata = businessManager->getContextManager()->get<TaskContext>( taskid, 1 );
        auto conn = businessManager->getNetWorkWarpper()->m_id_client_map[taskdata->tcpid];
        int64_t currentUid = conn->context<ContextDataType>().uid;

        if (currentUid == 0)
        {
            // 通过 Token 查找 uid
        }

        uint64_t currentGatewayid = generateDeviceTokenRequest.gatewayid();
        uint64_t currentDevideid = generateDeviceTokenRequest.deviceid();

        std::string genToken = genNewDeviceToken( currentGatewayid, currentDevideid );

        std::string newToken = GeeJoanMD5( genToken ).toString();

        int ret = ioTTable->updataDeviceToken( currentUid, currentGatewayid, currentDevideid,
                                               newToken );
        info( "IoTBusiness::GenerateDeviceToken ret = %d ", ret );
        if (ret == SUCCESS)
        {
            IoT::GenerateDeviceTokenRespose generateDeviceTokenRespose;
            generateDeviceTokenRespose.set_token( newToken );
            generateDeviceTokenRespose.set_time( util::timeMilli());

            std::string outString;

            if (generateDeviceTokenRequest.SerializePartialToString( &outString ))
            {
                // 序列化成
                businessManager->call200( taskid, outString );
                return 0;

            } else
            {
                businessManager->call500( taskid, " GenerateDeviceToken serial fail " );
                return -1;
            }
        } else
        {
            businessManager->call500( taskid, " GenerateDeviceToken fail " );
            return -1;
        }

    };
    findMyDevices_event_function = [&](int taskid, void *data, int len, void *userdata)
    {
        //TODO
        return -2;
    };

    findGateway_event_function = [&](int taskid, void *data, int len, void *userdata){
        IoT::FindSensorDataRequest findSensorDataRequest;

        if (!findSensorDataRequest.ParseFromArray( data,len ))
        {
            // 失败
            businessManager->call500(taskid, "error" );
            return -1;
        }

        // 解包成功
        auto taskdata = businessManager->getContextManager()->get<TaskContext>( taskid, 1 );
        auto conn = businessManager->getNetWorkWarpper()->m_id_client_map[taskdata->tcpid];
        int64_t currentUid = conn->context<ContextDataType>().uid;


        if (currentUid == 0)
        {
            // TODO 没有 登录  则 通过Token 查找当前 uid
        }

        std::vector<uint64_t> outGids;

        ioTTable->addOrFindGatewayId( currentUid, outGids );

        IoT::FindGatewayRespose findGatewayRespose;

        findGatewayRespose.set_time( util::timeMilli());
        for (auto gid : outGids)
        {
            findGatewayRespose.add_gatewayid( gid );
        }

        std::string outString;

        if (findGatewayRespose.SerializeToString( &outString ))
        {
            // 成功
            businessManager->call200( taskid, outString );
            return 0;
        } else
        {
            businessManager->call500(taskid, " error " );
            return -1;
        }

    };
}

void IoTMod::init_event()
{
    m_type_event_map.insert( {IOT_UPLOAD_SENSOR_DATA, uploadSensor_event_function} );
    m_type_event_map.insert( {IOT_FIND_SENSOR_DATA, findSensor_event_function} );
    m_type_event_map.insert( {IOT_CONTROL_DEVICE, controlDevice_event_function} );
    m_type_event_map.insert( {IOT_CONTROL_ACK, controlDeviceAck_event_function} );
    m_type_event_map.insert( {IOT_LOGIN_DEVICE, loginDevice_event_function} );
    m_type_event_map.insert( {IOT_HEART_BEAT, deviceHeartBeat_event_function} );
    m_type_event_map.insert( {IOT_CREATE_DEVICE, createDevice_event_function} );
    m_type_event_map.insert( {IOT_FIND_DEVICE_TOKEN, findDeviceToken_event_function} );
    m_type_event_map.insert( {IOT_GENERATE_DEVICE_TOKEN, generateDeviceToken_event_function} );
    m_type_event_map.insert( {IOT_FIND_MY_DEVICE, findMyDevices_event_function} );
    m_type_event_map.insert( {IOT_FIND_GATEWAY, findGateway_event_function} );

}

void IoTMod::init_finished()
{
    info( "IoTMod::init_finished ... " );
    ioTTable = businessManager->getDaoManager()->getTable<IoTDB>( 2 );
}
